buildTargetShaderBundleJson function
- required BuildInput buildInput,
- required BuildOutputBuilder buildOutput,
- required String manifestFileName,
- List<
Uri> includeDirectories = const [], - TargetShaderBundleAssetMode assetMode = TargetShaderBundleAssetMode.generatedTree,
- String? dataAssetName,
- int? glesLanguageVersion,
- bool copyToGeneratedTree = true,
- bool pruneGeneratedTree = true,
- String? owner,
- String? stamp,
- String? fileVariant,
Builds a shader bundle and removes backends the target cannot use.
TODO(shader-bundle-cache): the compiler runs on every hook rerun, since only
stamp callers skip it. Stamping the manifest and its sources here would let
an unrelated asset edit skip the compile.
In TargetShaderBundleAssetMode.generatedTree the trimmed bundle is copied
into the app's generated tree, recorded under the manifest name it was built
from. copyToGeneratedTree turns that off for a caller that publishes the
bundle itself (buildMaterials), and owner names the package the bundle
belongs to when the app's hook builds a dependency's shaders.
pruneGeneratedTree drops a tree copy the data-asset registration replaces.
flutter_scene's own hook turns that off: one build runs it several times
with different asset types, so its tree copy is the fallback for the runs
that have no data assets, not a leftover.
Implementation
Future<void> buildTargetShaderBundleJson({
required BuildInput buildInput,
required BuildOutputBuilder buildOutput,
required String manifestFileName,
List<Uri> includeDirectories = const [],
TargetShaderBundleAssetMode assetMode =
TargetShaderBundleAssetMode.generatedTree,
String? dataAssetName,
int? glesLanguageVersion,
bool copyToGeneratedTree = true,
bool pruneGeneratedTree = true,
String? owner,
String? stamp,
String? fileVariant,
}) async {
// ignore: deprecated_member_use_from_same_package
if (assetMode == TargetShaderBundleAssetMode.legacyOnly) {
throwRemovedAssetMode(
'TargetShaderBundleAssetMode.legacyOnly',
'TargetShaderBundleAssetMode.generatedTree',
);
}
// ignore: deprecated_member_use_from_same_package
if (assetMode == TargetShaderBundleAssetMode.dataAssetsIfAvailable) {
throwRemovedAssetMode(
'TargetShaderBundleAssetMode.dataAssetsIfAvailable',
'TargetShaderBundleAssetMode.generatedTree',
);
}
final emitDataAssets =
buildInput.config.buildDataAssets &&
assetMode == TargetShaderBundleAssetMode.dataAssetsRequired;
final result = await buildShaderBundleJson(
buildInput: buildInput,
buildOutput: buildOutput,
manifestFileName: manifestFileName,
includeDirectories: includeDirectories,
assetMode: switch (assetMode) {
TargetShaderBundleAssetMode.generatedTree =>
ShaderBundleAssetMode.legacyOnly,
TargetShaderBundleAssetMode.dataAssetsRequired =>
ShaderBundleAssetMode.dataAssetsRequired,
// Rejected above, before anything is compiled.
_ => ShaderBundleAssetMode.legacyOnly,
},
dataAssetName: dataAssetName,
glesLanguageVersion: glesLanguageVersion,
);
final output = File.fromUri(result.outputFile);
final bytes = trimShaderBundle(
output.readAsBytesSync(),
shaderBundleBackendsForBuild(buildInput),
);
output.writeAsBytesSync(bytes);
if (!copyToGeneratedTree) return;
final bundleFileName = result.outputFile.pathSegments.last;
final id = bundleFileName.endsWith('.shaderbundle')
? bundleFileName.substring(
0,
bundleFileName.length - '.shaderbundle'.length,
)
: bundleFileName;
if (emitDataAssets) {
if (!pruneGeneratedTree) return;
// A tree left by an earlier build would ship the same bundle twice.
GeneratedAssetTree.openExisting(
buildInput.packageRoot,
buildInput.packageName,
)
?..dropOwned(
GeneratedAssetFamily.shaderBundle,
owner: owner ?? buildInput.packageName,
)
..save();
return;
}
final tree = GeneratedAssetTree.open(
buildInput.packageRoot,
buildInput.packageName,
)..requireAssetEntry();
final copyUri = tree.fileUri(
GeneratedAssetFamily.shaderBundle,
nameId: id,
extension: '.shaderbundle',
variant: fileVariant,
);
writeGeneratedBytes(copyUri, bytes);
tree
..recordFile(
family: GeneratedAssetFamily.shaderBundle,
id: id,
uri: copyUri,
stamp: stamp ?? fnv1aHex(bytes),
owner: owner,
)
..save();
}