Description
Part of #130921
Option 1: Offer a library for making native_asset
build hooks easy.
Proof of concept build hook lib: https://github.com/bdero/test_native_assets/blob/master/hook/build.dart#L9-L138
To set up automated shaderbundle compilation, the user would:
- Define special json or yaml files in their project.
- Add a
hook/build.dart
file that invokes an imported function from theflutter_gpu
package:
void main(List<String> args) async {
await build(args, (config, output) async {
await buildShaderBundle(
buildConfig: config,
buildOutput: output,
manifestFileName: 'mybundle.shaderbundle.json');
});
}
- Add watch rules for assets in the project's build directory.
Option 2: Use an Asset Transformer.
Make a simple transformer package that just ingests a manifest text file and finds/invokes impellerc, replacing this temp solution.
A few thoughts:
- I'm not sure what the current status is for hot reloading in asset transformers, but we'll eventually want to support hot reloading shader bundles (which would require somehow instructing the tool to watch a list of dependent files for changes), but I don't see that as a super high priority right now.
- Same goes for model imports in Flutter Scene, which is usually a simpler 1-1 model import situation, but will sometimes require watching multiple files similar to the shader bundle case (for example, glTFs with separated image files, or OBJs with separated MTLs).
- The importer is locked to a specific version of ImpellerC. Rather than publish it on pub.dev, we should ship it as an SDK package under the
packages
directory in the flutter/flutter repo with an integration test ensuring that it doesn't break against the version of impellerc shipping in the engine artifacts. - Not a huge deal, but it would be nice if we could implicitly activate this particular transformer for all projects when they depend on the
flutter_gpu
SDK package automatically. Without this, I believe users of Flutter GPU will need to both depend on and activate the asset transformer by adding configuration similar to the following inpubspec.yaml
:
dependencies:
flutter_gpu:
sdk: flutter
dev_dependencies:
flutter_gpu_shaders:
sdk: flutter
flutter:
assets:
- path: *.shaderbundle.yaml
transformers:
- package: flutter_gpu_shaders
Option 3: Add support directly to the Flutter tool.
Flutter GPU shaders are stored in libraries, and these libraries can be deserialized from "shader bundle" files.
For this task, add support to the Flutter tool for importing a collection of shader files as a shader bundle.
Here's an example of a shader bundle defined in a package pubspec.yaml
file:
### pubspec.yaml ###
- shader_bundle:
- CoolShaderBundle:
- FlatShadeVertex:
type: vertex
file: assets/shaders/flatshade.vert
- FlatShadeFragment:
type: fragment
file: assets/shaders/flatshade.frag
This creates one shader bundle called "CoolShaderBundle" with two shader inputs: "FlatShadeVertex" and "FlatShadeFragment".
To produce this shader bundle asset, the flutter tool should run impellerc
with the --shader_bundle
parameter. Taking the example above, the call should look like this:
impellerc --sl="CoolShaderBundle.shaderbundle" \
--shader_bundle="{\
\"FlatShadeVertex\": { \
\"type\": \"vertex\", \
\"file\": \"assets/shaders/flatshade.vert\" \
}, \
\"FlatShadeVertex\": { \
\"type\": \"vertex\", \
\"file\": \"assets/shaders/flatshade.vert\" \
} \
} \
}";
If any of the input source shader files have change, then the output shader bundle file (CoolShaderBundle.shaderbundle
) needs to be rebuilt.
See also the Flutter GPU doc.
The shader bundle spec
For Flutter GPU's MVP, ImpellerC's --shader_bundle
accepts a JSON string in the following form:
{
"$shader_name" {
"type": "[vertex|fragment]",
"file": "$file_name"
}
}
Later on, other per-shader parameters can be supported, such as ("language" and "entry_point").
Building shader bundles manually
Up until now, I've been building shader bundles manually in order to bootstrap some renderer projects. These bundles are produced using the impellerc
executable shipped in the engine artifacts.
Here's an example of a valid invocation of ImpellerC, which builds a shader bundle asset named "assets/base.shaderbundle" with 5 builtin shaders:
BUNDLE_OUTPUT_FILENAME="assets/base.shaderbundle"
BASE_BUNDLE_JSON='
{
"SimpleVertex": {
"type": "vertex",
"file": "shaders/flutter_scene_simple.vert"
},
"SimpleFragment": {
"type": "fragment",
"file": "shaders/flutter_scene_simple.frag"
},
"UnskinnedVertex": {
"type": "vertex",
"file": "shaders/flutter_scene_unskinned.vert"
},
"SkinnedVertex": {
"type": "vertex",
"file": "shaders/flutter_scene_skinned.vert"
},
"UnlitFragment": {
"type": "fragment",
"file": "shaders/flutter_scene_unlit.frag"
}
}'
SHADER_BUNDLE_JSON=$(echo $2 | tr -d '\n')
impellerc --sl="$BUNDLE_OUTPUT_FILENAME" --shader-bundle="$BASE_BUNDLE_JSON"
Note that the actual names of the shaders in the bundle (SimpleVertex, SimpleFragment, etc) are entirely the user's choice.
How manually built shader bundles are imported.
Here's a simplified example of a Flutter GPU ShaderLibrary being deserialized from a shader bundle (as seen in the flutter_scene
package):
import 'package:flutter_gpu/gpu.dart' as gpu;
final String _kBaseShaderBundlePath =
'packages/flutter_scene/assets/base.shaderbundle';
gpu.ShaderLibrary get baseShaderLibrary {
gpu.ShaderLibrary? result = gpu.ShaderLibrary.fromAsset(_kBaseShaderBundlePath);
if (result != null) {
return result!;
}
throw Exception(
"Failed to load base shader bundle! ($_kBaseShaderBundlePath)");
}
From here, a ShaderBundle can be used by looking up shader names
gpu.Shader? myVertexShader = baseShaderLibrary["UnlitVertex"];
Metadata
Metadata
Assignees
Labels
Type
Projects
Status